package indexation;

import java.awt.geom.NoninvertibleTransformException;
import java.io.*;

import java.text.Normalizer;
import java.util.*;

@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
public class tokenisation {
	
	static List<HashMap<String,ArrayList<String>>> index = new ArrayList<HashMap<String,ArrayList<String>>>();
	static List<HashMap<String,String>> dico = new ArrayList<HashMap<String,String>>();
	static HashMap<String,String> numberWordsOfDocument = new HashMap<String,String>();
	
	// fonction pour supprimer les accents
	public static String removeAccent(String source) {
		return Normalizer.normalize(source, Normalizer.Form.NFD).replaceAll("[\u0300-\u036F]", "");
	}
	
	/*
	 * Fonction pour ajouter de nouveaux mots d'un document dénommé nameFile dans l'index
	 * On verifie d'abord si le mot n'est pas dans la liste de mot non important
	 * avant de l'ajouter dans l'index
	 * */
	public static void createList(String nameFile,ArrayList<String> nonimportantwords) {
		
		String[] chaine ;
		int number = 0;
		
		try {
			InputStream ips=new FileInputStream("files/"+nameFile+".txt"); 
			InputStreamReader ipsr=new InputStreamReader(ips);
			BufferedReader br=new BufferedReader(ipsr);
			String ligne;
			
			while ((ligne=br.readLine())!=null){
				ligne = removeAccent(ligne);
				ligne = ligne.replaceAll("[\\p{P} \\t\\n\\r]",":");
				ligne = ligne.replaceAll("::",":");

				chaine = ligne.split(":");
				for (int i = 0; i < chaine.length; i ++) {
					// on verifie si chaine nest pas contenu dans la liste de mots non importants
					chaine[i] = chaine[i].toLowerCase();
					if (!nonimportantwords.contains(chaine[i])) {
						findIndex(chaine[i],nameFile);				
					}else {
						;//System.out.println("test");
					}
					number++;
					
				}
			}
			numberWordsOfDocument.put(nameFile, String.valueOf(number));
			br.close(); 
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		HashMap<String,ArrayList<String>> listIndex = new HashMap<String,ArrayList<String>>();
		List<HashMap<String,ArrayList<String>>> inde = new ArrayList<HashMap<String,ArrayList<String>>>();
		listIndex.put("index",new ArrayList<String>());
		inde.add(listIndex);
		// ajouter index dans la liste inde
		// ajouter un identifiant de fichier dans une liste pour un index donné
		//
	
	}
	// Fonction qui permet de créer une nouvelle entrée dans l'index
	public static void addIndex(String oneindex, String id) {
		HashMap<String,ArrayList<String>> listIndex = new HashMap<String,ArrayList<String>>();
		listIndex.put(oneindex,new ArrayList<String>());
		listIndex.get(oneindex).add(id);
		index.add(listIndex);		
	}
	
	// Regarder si un mot se trouve dans l'index
	// Si c'est le cas alors incrémenter sa fréquence
	// Sinon l'ajouter
	//@SuppressWarnings({ "rawtypes", "unchecked" })
	public static boolean findIndex(String indexSearch, String id) {
		Iterator it  = index.iterator();
		int i=0;
		while (it.hasNext()) {
			HashMap<String,ArrayList<String>> myindex = (HashMap<String,ArrayList<String>>)it.next();
			if (myindex.containsKey(indexSearch)) {
				i=1;
				int ident = containsIdentifier(myindex.get(indexSearch),id);
				if (ident == -1) {
					System.out.println("ajout dun nouveau id dans "+indexSearch);
					//ajouter page6:1
					id = id+":"+"1";
					myindex.get(indexSearch).add(id);
				} else {
					myindex.get(indexSearch).set(ident, incrementeFrequencies(myindex.get(indexSearch).get(ident)));
					System.out.println("le mot  "+indexSearch+" est deja localise dans cette page");
					// int position = myindex.get(indexSearch).indexOf(id);
					// set(position,inexSerach:nboccurences);
				}
				System.out.println("mon index "+myindex);
			} /*else {
				System.out.println("dans le elseeeeeee");//addIndex(indexSearch);
			}*/
		}
		if (i == 0) {
			System.out.println("En vue d'ajouter l'index");
			id = id+":"+"1";
			addIndex(indexSearch,id);
		}
	
		return true;
	}
	//@SuppressWarnings({ "rawtypes" })
	public static int containsIdentifier(ArrayList<String> listId, String id) {
		
		Iterator it  = listId.iterator();
		while (it.hasNext()) {
			String identificator = (String) it.next();
			if  (identificator.split(":")[0].equals(id)) {
				return listId.indexOf(identificator);
			}
		}
		
		return -1;
	}
	
	public static String incrementeFrequencies(String identifiant) {
		
		String[] temp = identifiant.split(":");
		int i = Integer.parseInt(temp[1]);
		i++;
		identifiant = temp[0]+":"+i;
		return identifiant;
	}
	

	// Fonction qui permet de trier une liste
	//@SuppressWarnings({ "unused"})
	public static ArrayList<String> triBulle(ArrayList<String> tableau)
    {
		int longueur=tableau.size();
		int indice = 0;

		//do
		for(int j = 0; j < longueur-1;j++)
			{
        	for(int i=0;i<longueur-1;i++)
        	{
            //Teste si 2 éléments successifs sont dans le bon ordre ou non
        		if(elementAt(i,tableau)<elementAt(i+1,tableau))
        			{
        			//s'ils ne le sont pas on échange leurs positions
        			// A verifier un passage par valeur ou par adresse
        			permute(tableau,i,i+1);
        			
                }
            }
        	//indice++;
         }
    //while(indice > longueur);
		return tableau;
    }
	public static int elementAt(int i,ArrayList<String> tableau) {
		String element = tableau.get(i);
		//System.out.println("elemeantAt(i) "+element.split(":")[1]);
		return Integer.parseInt(element.split(":")[1]);
	}
	
	public static void permute(ArrayList<String> tableau,int i,int j) {
		String temp = tableau.get(i);
		tableau.set(i,tableau.get(j));
		tableau.set(j,temp);
		
	}
	
	// Fonction qui permet de trier un index déjà créé
	//@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void trierindex() {
		int i = 0;
		Iterator it  = index.iterator();
		while (it.hasNext()) {
			HashMap<String,ArrayList<String>> myindex = (HashMap<String,ArrayList<String>>)it.next();
			Iterator iterator =	myindex.keySet().iterator();
				if (iterator.hasNext()){
					String key =(String) iterator.next();
					HashMap<String,String> map = new HashMap<String,String>();
					map.put(key,String.valueOf(i));
					i++;
					dico.add(map);
					triBulle(myindex.get(key));
				}
		}
	}
	
	// Fonction qui permet d'enregistrer l'index dans le ficher inverse et le dictionnaire dans le fichier de dictionnaire
	public static void savePostingsAndDico(List<HashMap<String,ArrayList<String>>> indexe) {
		
		ObjectOutputStream out_postings;
		ObjectOutputStream out_dico;
		
		try {
			out_postings = new ObjectOutputStream(new FileOutputStream("files/postings.dat"));
			out_postings.writeObject(index);
			
			out_dico = new ObjectOutputStream(new FileOutputStream("files/dico.dat"));
			out_dico.writeObject(dico);
			
			System.out.println("Sauvegarde des postings et du dictionnaire réussie.");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	// Permet de charger le fichier d'inverse et le fichier de dictionnaire
	//@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void loadPostingsAndDico() {
		
		ObjectInputStream in_postings;
		ObjectInputStream in_dico;
		
		try {
			in_postings = new ObjectInputStream(new FileInputStream("files/postings.dat"));
			List<HashMap<String,ArrayList<String>>> postings = (List<HashMap<String,ArrayList<String>>>) in_postings.readObject();
			index = postings;
			in_dico = new ObjectInputStream(new FileInputStream("files/dico.dat"));
			List<HashMap<String,String>> dicos = (List<HashMap<String,String>>) in_dico.readObject();
			dico = dicos;
			System.out.println("Chargement des postings et du dictionnaire réussie.");
			Iterator it  = dicos.iterator();
			/*while (it.hasNext()) {
				HashMap<String,String> dictio = (HashMap<String,String>)it.next();
			//	System.out.println("newtest get: "+dictio.get("deep"));
				Iterator iterator =	dictio.keySet().iterator();
					if (iterator.hasNext()){
						String key = (String) iterator.next();
						if (key.equals("massachusetts")) {
						;//System.out.println("key de ce keyword: "+key);
						//iterator.hasNext();
					    // System.out.println("value de ce keyword: "+dictio.get(key));
						}
					}
			}*/
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//SuppressWarnings({ "rawtypes", "unchecked" })
	public static int getWordDico(List<HashMap<String,String>> dicotio,String word) {
			Iterator it = dicotio.iterator();
			while (it.hasNext()) {
				HashMap<String,String> wordInDiction = (HashMap<String,String>) it.next();
				if (wordInDiction.get(word)!=null) {
					// on renvoie son numéro d'index au niveau des postings
					//System.out.println("on renvoie son numéro d'index au niveau des postings");
					return Integer.parseInt(wordInDiction.get(word));
				}
			}
		return -1;
	}
	public static boolean contains(ArrayList<String> liste,String page) {
		Iterator it = liste.iterator();
		while (it.hasNext()) {
			String newpage = (String) it.next();
			if (page.split(":")[0].equals(newpage.split(":")[0]))
				return true;
		}
		return false;
	}
	
	// Permet de faire une recherche booleenne et prenant en paramètre une requete
	public static boolean booleanSearch(List<HashMap<String,ArrayList<String>>> index,List<String> request) {
	//	System.out.println("getWordDico(dico, request.get(0))  : "+getWordDico(dico, request.get(1)));
		//System.out.println("index.get(9))  : "+index.get(99).get(request.get(1)));
		HashMap<String,ArrayList<String>> liste = index.get(getWordDico(dico, request.get(0)));
		Iterator it = liste.get(request.get(0)).iterator();
		while (it.hasNext()) {
			String page = (String) it.next();
			//System.out.println("page : "+page);
			int j = 1;
			while (j < request.size()) {
				//System.out.println("request.get(j) :" + request.get(j));
				if (request.get(j).equals("AND")) {
					j++;
					if (contains(index.get(getWordDico(dico, request.get(j))).get(request.get(j)),page)) {
						j++;
					} else break;
				} else
				if (request.get(j).equals("NOT")) {
					//System.out.println("NOTTTTTTTT");
					j++;
					if (!contains(index.get(getWordDico(dico, request.get(j))).get(request.get(j)),page)) {
						j++;
					} else break;
				} else
				if (request.get(j).equals("OR")) {
					//System.out.println("ORRRRRRR");
					j++;
					j++;
				} 
			}
			/*while ((j < request.size())&&( contains(index.get(getWordDico(dico, request.get(j))).get(request.get(j)),page))) {
				j++;
			}*/
			if (j >= request.size()) 
				System.out.println("Cette page est innteressante : " +page); // ajouter page aux pages à afficher
		}
		
		return false;
		//index.get(dico.get)
	
	}
	
	// Permet de calculer les pondération : tf*idft pour chacun des mots dans un document donné
	public static void calculePonderation(List<HashMap<String,ArrayList<String>>> postings,ArrayList<String> nonimportantwords) {
		Iterator it  = postings.iterator();
		while (it.hasNext()) {
			HashMap<String,ArrayList<String>> myindex = (HashMap<String,ArrayList<String>>)it.next();
			Iterator iterator =	myindex.keySet().iterator();
				if (iterator.hasNext()){
					String key =(String) iterator.next();
					ArrayList<String> ponderation = new ArrayList<String>();
					ponderation = myindex.get(key);
					for (int i=0; i < ponderation.size();i++) {
						String poids = ponderation.get(i);
						double idft = Math.log(20/ponderation.size());
						//double tf = Double.parseDouble(poids.split(":")[1])/Double.parseDouble(numberWordsOfDocument.get(poids.split(":")[0]));
						double tf = Double.parseDouble(poids.split(":")[1])/countWordsOfDocument(poids.split(":")[0],nonimportantwords);
						//countWordsOfDocument
						poids = poids+":"+(tf*idft);
						ponderation.set(i,poids);
					}
				}
		}
	}
	public static void afficheIndex(List<HashMap<String,ArrayList<String>>> postings) {
		Iterator it  = postings.iterator();
		while (it.hasNext()) {
			HashMap<String,ArrayList<String>> myindex = (HashMap<String,ArrayList<String>>)it.next();
			Iterator iterator =	myindex.keySet().iterator();
				if (iterator.hasNext()){
					String key =(String) iterator.next();
					ArrayList<String> ponderation = new ArrayList<String>();
					ponderation = myindex.get(key);
					System.out.println("ponderation "+ponderation);
				}
		}
	}
	
	// effectue la recherche vectoriel
	public static void rechercheVectoriel(List<HashMap<String,ArrayList<String>>> postings,List<String> request) {
		double var1=0,var2=0,var3=0;
		ArrayList<String> distanceCosinus = new ArrayList<String>(); 
		for (int i=1; i < 21;i++) {
			for (int j=0; j < request.size();j++) {
				// getWeightWordInDocument(String word, String filei)
				Iterator it  = postings.iterator();
				while (it.hasNext()) {
					HashMap<String,ArrayList<String>> myindex = (HashMap<String,ArrayList<String>>)it.next();
					Iterator iterator =	myindex.keySet().iterator();
						if (iterator.hasNext()){
							String key =(String) iterator.next();
							//if (key.equals(request.get(j))) {
								ArrayList<String> listPage = new ArrayList<String>();
								listPage = myindex.get(key);
								Iterator itt  = listPage.iterator();
								while (itt.hasNext()) {
									String word = (String)itt.next();
									if ((word.split(":")[0]).equals("file"+i)) {
										// je dois pouvoir calculer poidafiei à la volée sans la fonction en haut
										double poidafilei= Double.parseDouble(word.split(":")[2]);
										double idft = Math.log(20/listPage.size());
										//double poidafilei = idft * Double.parseDouble(word.split(":")[1])/Double.parseDouble(numberWordsOfDocument.get(word.split(":")[0]));
										
										double tf = 0;
										if (request.contains(key))
											tf = 1;
										var1 +=poidafilei*idft*tf;
										var2 += poidafilei*poidafilei;
										var3 += (idft*tf)*(idft*tf);
										break;
									}
								}
							//}
						}
				}
				//getWeightWordInRequest(String word, List request)
			}
			
			// calculer la distance d'avec le document D var!1/racine var2 + racine var3n
			distanceCosinus.add("file"+i+":"+String.valueOf(var1/(Math.sqrt(var2))*Math.sqrt(var3)));
			//System.out.println("valeur "+var1/(Math.sqrt(var2))*Math.sqrt(var3));
			var1=var2=var3=0;
		}
		
		// trier distance cosinus
			triABulle(distanceCosinus);
		// afficher les 10 meilleurs résultats
			System.out.println("Voici les 10 meilleurs résultas :");
			for (int i =0; i< 10; i++)
				System.out.println("Ce document est interessant :"+distanceCosinus.get(i).split(":")[0]+" avec" +
						" une distance cosinus de "+distanceCosinus.get(i).split(":")[1]);
	}
	public static ArrayList<String> triABulle(ArrayList<String> tableau)
    {
		int longueur=tableau.size();
		int indice = 0;

		//do
		for(int j = 0; j < longueur-1;j++)
			{
        	for(int i=0;i<longueur-1;i++)
        	{
            //Teste si 2 éléments successifs sont dans le bon ordre ou non
        		if(elementAtt(i,tableau)<elementAtt(i+1,tableau))
        			{
        			//s'ils ne le sont pas on échange leurs positions
        			// A verifier un passage par valeur ou par adresse
        			permute(tableau,i,i+1);
        			
                }
            }
        	//indice++;
         }
    //while(indice > longueur);
		return tableau;
    }
	public static double elementAtt(int i,ArrayList<String> tableau) {
		String element = tableau.get(i);
		//System.out.println("elemeantAt(i) "+element.split(":")[1]);
		return Double.parseDouble(element.split(":")[1]);
	}
	
	public static double countWordsOfDocument(String nameFile,ArrayList<String> nonimportantwords) {
		InputStream ips;
		double number=0;
		try {
			ips = new FileInputStream("files/"+nameFile+".txt");
		
		InputStreamReader ipsr=new InputStreamReader(ips);
		BufferedReader br=new BufferedReader(ipsr);
		String ligne;
		
		
		while ((ligne=br.readLine())!=null){
			ligne = removeAccent(ligne);
			ligne = ligne.replaceAll("[\\p{P} \\t\\n\\r]",":");
			ligne = ligne.replaceAll("::",":");

			String[] chaine = ligne.split(":");
			number+=chaine.length;
		}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return number;
	}
	public static void main(String args[]) {
		Calendar calendar1 = Calendar.getInstance();
		InputStream stream=null;
		BufferedReader breader = null;
		InputStreamReader ipr = null;
		ArrayList<String> nonimportantwords =  new ArrayList<String>();
		ArrayList<String> request = new ArrayList<String>();
				
			for (int i=1;i < args.length; i ++)  {
			//	System.out.println(" args de i "+args[i]);
				request.add(args[i]);
			}
		
		// créer la liste des mots non importants
		try {
			stream = new FileInputStream("files"+ File.separatorChar+"stoplist.txt");
			ipr=new InputStreamReader(stream);
			breader=new BufferedReader(ipr);
			String ligne;
			
			while ((ligne=breader.readLine())!=null){
				//System.out.println("lignee"+ligne+"lligne");
				nonimportantwords.add(ligne);
			}
			breader.close(); 
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		/*		
		for (int i=1; i<20;i++) {
			createList("file"+i,nonimportantwords);
		}
		trierindex();
		calculePonderation(index,nonimportantwords);
		savePostingsAndDico(index);*/
		loadPostingsAndDico();
		/*Iterator it  = dico.iterator();
		while (it.hasNext()) {
			HashMap<String,String> dictio = (HashMap<String,String>)it.next();
		//	System.out.println("newtest get: "+dictio.get("deep"));
			Iterator iterator =	dictio.keySet().iterator();
				if (iterator.hasNext()){
					String key = (String) iterator.next();
					//if (key.equals("massachusetts")) {
					System.out.println("key de ce keyword: "+key);
					//iterator.hasNext();
				     System.out.println("value de ce keyword: "+dictio.get(key));
					//}
				}
		}*/
		//request.add("massachusetts");request.add("AND");request.add("washington");
		//request.add("OR");request.add("radiation");
		//request.add("OR");request.add("cheikh");
		if (args[0].equals("-b"))
		    booleanSearch(index,request);
		
		if (args[0].equals("-v"))
			rechercheVectoriel(index, request);
		
		 Calendar calendar2 = Calendar.getInstance();

		    System.out.println(calendar2.getTime().getTime() - calendar1.getTime().getTime());
		try {
			breader.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
